/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 *
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_ui.htm
 *
 * Zhiqim UI is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

+(function(Z)
{//BEGIN
// @version v1.1.0 @author zouzhigang 2015-11-12 新建与整理

/************************************************************************/
//下拉列表，包括属性和方法
/************************************************************************/
// 1、配置方式，必须包括data-role="dropdown"表示是下拉列表
// 2、可选属性data-onchange表示修改的函数，类似于select
// 2、可选属性data-options值为样式格式event:click;width:160px;item-width:160px;
// 3、支持的参数值
//     1)event                  表示该窗口的触发方式，click|hover，默认click
//     2)width                  表示下拉列表宽度，默认等于elem的宽度，类似于select
//     3)height                 表示下拉列表高度，默认200px时会出现滚动条，可以通过设计该值进行修改
//     4)item-width             表示下拉项的宽度，默认等于width，一行一个类似于select，如果设置成width/2，则表示一行两个
// 4、举例如下：
// <div class="z-dropdown" data-role="z-dropdown" data-options="" data-onchange="onChangeProvice" style="width:160px;">
//     <span class="z-default" id="proviceId" value="2">湖南省</span><span class="z-float-right"><i class="z-arrow"></i></span>
//     <ul class="z-list">
//            <span value="1">广东省</span>
//            <span value="2" selected>湖南省</span>
//            <span value="3">广西壮族自治区</span>
//            <span value="3">江西省</span>
//        </ul>
// </div>
/************************************************************************/
/********************************************/
//提示类定义，包括属性和方法
/********************************************/
Z.Dropdown = Z.Class.newInstance();
Z.Dropdown.prototype =
{
    defaults :
    {//缺省值
        elem: null,
        hasSelected: true//firefox第一次focus不会show
    },

    init: function()
    {//初始化
        this.$elem = Z.$elem(this.elem, "Z.Dropdown");

        this.$default = this.$elem.find(".z-default");
        this.$input = this.$default.children('input');
        this.$arrow = this.$elem.find("i.z-float-right.z-font");
        this.$list = this.$elem.find(".z-list");
        this.$spans = this.$list.find("span");
        if (this.$list.length == 0)
            return;

        //为 z-list 添加点击事件
        this.$select = this.$elem.parent().find("select")[0];
        this.$list.click(this.select, this);

        //获取配置的属性
        var options = Z.AR.toObject(this.$elem.attr("data-options"), ";");
        var expression = this.$elem.attr("data-onchange");
        if (Z.T.isString(expression))
            this.onchange = Z.evals(expression);

        //初始化列表高度
        this.event = options && options.event || "click";
        this.stop = options && options.stop || "false";
        var maxHeight = Z.S.prefixNum(options && options.maxHeight || "200");
        this.$list.css("maxHeight", maxHeight);

        //初始化条目宽高
        this.width = options && options.width || this.$elem.offsetWidth();
        var itemWidth = Z.S.prefixNum(options && options.itemWidth || this.width);
        var itemHeight = Z.S.prefixNum(options && options.itemHeight || "30");
        this.$spans.css({width: itemWidth, height: itemHeight, lineHeight: itemHeight-6});

        //把条目的高度缓存起来
        this.$list.show();
        this.itemHeight = this.$spans.offsetHeight();
        this.$list.hide();

        //初始化成功
        this.status = 0;

        //初始化注册移入移出事件，鼠标在元素和提示上显示
        if (this.event == "click")
        {
            this.$elem.click(this.show, this);
            Z(document).click(this.hide, this);
        }
        else
        {
            this.$elem.mouseover(this.show, this);
            this.$elem.mouseout(this.hide, this);
            this.$list.mouseover(this.show, this);
            this.$list.mouseout(this.hide, this);
        }

        if (this.$input.length > 0)
        {
            this.$input.on('focus',this.focus, this);
            this.$input.on('input',this.show, this);
            this.$input.on('blur',this.blur, this);
        }
    },
    focus: function(e)
    {
        this.$input.attr("placeholder", this.$input.attr("data-value"));
        this.$input.val("");

        if (Z.B.firefox && this.hasSelected)
        {//firefox第一次focus不会show
            this.hasSelected = false;
            this.show(e);
        }
    },
    show: function(e)
    {
        if (this.stop == "true")
        {//默认为false,即向上冒泡，以支持多个下拉列表时相互关闭，当父节点有click事件时，可设置为true，不冒泡
            Z.E.stop(e);
        }

        var target = Z.E.target(e);
        if (this.event == "click" && this.status == 1 && !(target instanceof HTMLInputElement))
        {//第二次点击表示关闭，如果input下点击不处理，箭头处理
            this.close();
            return;
        }

        //把列表恢复为初始模式
        this.status = 1;
        this.$elem.addClass("z-active");
        this.$arrow.removeClass("z-arrowhead-down").addClass("z-arrowhead-up");

        if (this.$input.length > 0)
        {
            this.$list.removeClass("z-none").css("height", "auto");
            this.$spans.removeClass("zi-hide");

            if (target instanceof HTMLInputElement)
            {//如果是从input点击的执行搜索，箭头不执行，显示全部
                this.search();
            }
        }

        //定义到元素的下方
        var top = this.$elem.offsetHeight() - 2;//上下边框2px
        var left = -1;//左边框1px

        this.$list.inBlock().css({top: top, left: left, width: this.width});

        var listRect = this.$list[0].getBoundingClientRect();
        var topBody = listRect.top;
        var height = listRect.height;

        if (topBody > height && Z.D.clientHeight() - topBody - height < 0)
        {//如果顶部够高，底部不够高时，则向上弹出
            top = top - height - this.$elem.offsetHeight() + 2;
            this.$list.css("top", top);
        }
    },
    hide:function(e)
    {
        if (this.stop == "true")
        {//默认为false,即向上冒泡，以支持多个下拉列表时相互关闭，当父节点有click事件时，可设置为true，不冒泡
            Z.E.stop(e);
        }

        //鼠标在元素和提示中间不关闭
        var x = Z.E.clientX(e);
        var y = Z.E.clientY(e);
        var tx = this.$elem.clientX();
        var ty = this.$elem.clientY();
        var tw = this.$elem.offsetWidth();
        var th = this.$elem.offsetHeight();

        if (x > tx && x < (tx+tw) && y > ty && y < (ty+th))
            return;

        this.close();
    },
    search: function()
    {
        var val = this.$input.val();
        // 用克隆节点操作，再一次性替换当前节点
        var $list_clone = this.$list[0].cloneNode(true);
        var $spans_clone = $list_clone.querySelectorAll("span");
        // 显示数量
        var num_show = this.$spans.length;
        // 如果没有内容，全部展示
        if (!val)
        {
            var $spans_hide = $list_clone.querySelectorAll("span.zi-hide");
            $spans_hide.forEach(function($span)
            {
                $span.className = "";
            })
            $list_clone.className = "z-list";
        }
        else
        {
            $spans_clone.forEach(function($span)
            {//检索字符串是否存在
                if($span.innerText.indexOf(val) > -1)
                {
                    $span.className = "";
                }
                else
                {
                    $span.className = "zi-hide";
                    num_show--;
                }
            });
            if (!num_show)
            {
                $list_clone.className = "z-list z-none";
                num_show = 1;
            }
        }
        // 设置列表高度
        $list_clone.style.height = (this.itemHeight * num_show + 2) + "px";
        // 插入新节点，移除老节点
        this.$elem.append($list_clone);
        this.$list.remove();
        // 重定义变量
        this.$list = this.$elem.find(".z-list").click(this.select, this);
        this.$spans = this.$list.find("span");
    },
    blur: function(e)
    {//输入框退出时，恢复输入框
        this.$input.val(this.$input.attr("data-value"));
    },
    setValue: function(value)
    {
        if (Z.V.isEmpty(value))
            return;

        var $selected;
        this.$spans.each(function(item)
        {
            var $span = Z(item);
            if (value == $span.attr("value")){
                $selected = $span;
                return true;
            }
        });

        if ($selected)
        {//找到
            this.selected($selected);
            //设置值时，需要检查是否是z-select,是同步到select中
            var selectId = this.$elem.attr("data-id");
            if (selectId)
            {
                var sel = Z.D.id(selectId);
                if (sel){
                    Z.Select.click($selected[0], sel);
                }
            }
        }
    },
    select: function(e)
    {
        Z.E.stop(e);
        this.selected(Z(Z.E.target(e)));
        Z.Select.call(this.$select, e);
    },
    selected: function($selected)
    {
        this.$spans.each(function(item)
        {//先清理选中
            Z(item).removeClass("z-selected").removeAttr("selected");
        });

        $selected.addClass("z-selected");

        if (this.$input.length > 0)
        {
            this.$input.attr('data-value', $selected.text()).val($selected.text());
        }
        else
        {
            this.$default.val($selected.val());
            this.$default.text($selected.text());
        }

        this.hasSelected = true;
        this.close();

        if (this.onchange)
          this.onchange($selected.val());
    },
    close: function()
    {
        this.status = 0;
        this.$elem.removeClass("z-active");
        this.$arrow.removeClass("z-arrowhead-up").addClass("z-arrowhead-down");
        this.$list.hide();
    },
    remove: function()
    {
        this.$elem.remove();
    }
};

/********************************************/
//刷新静态函数和第一次加载
/********************************************/
Z.Dropdown.load = function(target)
{//加载
    Z.$selector("[data-role=z-dropdown]", target).each(function(elem){
        new Z.Dropdown({elem: elem});
    });
};

Z.onload(Z.Dropdown.load);

/********************************************/
//选择框定义和加载转换成下拉列表对象
/********************************************/
Z.Select = function(e)
{
    Z.E.stop(e);
    Z.Select.click(Z.E.target(e), this);
}

Z.Select.click = function(target, elem)
{
    var index = Z(target).attr("index");
    var oldIndex = elem.selectedIndex;
    for (var i=0;i<elem.length;i++)
    {//修改选中
        elem.options[i].selected = (index == i);
    }
    if (elem.onchange && oldIndex != index){
        elem.onchange();
    }
    if (elem.onblur){
        elem.onblur();
    }
};

Z.Select.get = function(id)
{
    var $role = Z("[data-id="+id+"]");
    if ($role.length == 0)
        return null;

    return new Z.Dropdown({elem: $role[0]});
};

Z.Select.load = function(target)
{
    Z.$selector(".z-role-select", target).each(function(elem)
    {//先删除目标范围内的下拉列表
        new Z.Dropdown({elem: elem}).remove();
    });

    Z.$selector("select[data-role=z-select],select[data-role=z-select-search]", target).each(function(elem)
    {//再加载目标范围内的数据
        var random = "Z_Select_"+Z.random(10);
        var $elem = Z(elem).hidden().attr("data-id", random);
        var isSearch = $elem.attr("data-role") == "z-select-search";

        var width = $elem.offsetWidth();
        var height = $elem.offsetHeight();

        var $cover = Z.$cover($elem);

        var id = Z.S.trim($elem.attr("id"));
        var name = Z.S.trim($elem.attr("name"));
        var options = "event:click;" + Z.S.trim($elem.attr("data-options"));
        var classes = Z.S.trim($elem.attr("data-class"));
        var type = $elem.attr('data-type');

        var dropdown = '<div class="z-dropdown z-role-select">'
                     + '<span class="z-default z-text-clip" value=""></span><i class="z-float-right z-font z-arrowhead-down"></i>'
                     + '<ul class="z-list"></ul>'
                     + '</div>';

        var $role = Z(dropdown).appendTo($cover)
            .css({position: "absolute", left: 0, top: 0, width: width, height: height})
            .cssMaybe("padding-left", $elem.css("paddingLeft"))
            .cssMaybe("padding-right", $elem.css("paddingRight"))
            .cssMaybe("padding-top", $elem.css("paddingTop"))
            .cssMaybe("padding-bottom", $elem.css("paddingBottom"))
            .addClass(classes)
            .attr("id", random).attr("data-id", id).attr("data-name", name)
            .attr("data-options", options);

        //如果是模糊查找选择框
        if(isSearch)
        {
            $role.find(".z-default").append('<input type="text" class="zi-bd-none zi-w100p zi-h100p" placeholder="请选择" data-value="" value="">');
        }

        var hasSelected = null;
        for (var i=0;i<elem.length;i++)
        {
            var option = elem.options[i];

            var span = '<span index="'+i+'" value="'+option.value+'"';
            if (option.selected){
                hasSelected = option;
                span += " selected"
            }
            span += '>'+(Z.V.isEmpty(option.text)?"&nbsp;":option.text)+'</span>';
            var $span = Z(span);

            //如果有配置点击事件，则设置
            var optionClick = option.getAttribute("onclick");
            if (optionClick) {
                $span[0].setAttribute("onclick", optionClick);
            }

            $role.find('.z-list').append($span);
        }

        //如果未选中取第一个
        if (hasSelected == null){
            hasSelected = (elem.length>0)?elem.options[0]:null;
        }

        if (hasSelected)
        {
            if (isSearch){
                $role.find('.z-default > input').attr("data-value", hasSelected.text).val(hasSelected.text);
            }
            else{
                $role.find('.z-default').attr("value", hasSelected.value).text(hasSelected.text);
            }
        }

        //转成下拉列表
        new Z.Dropdown({elem: $role[0]});
    });
};

Z.onload(Z.Select.load);

//END
})(zhiqim);
